package com.lry.basic.juc;


import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.LockSupport;

public class MyCasFailLock {


    volatile int state;
    BlockingQueue<Thread> waiter = new LinkedBlockingQueue();

    private static final Unsafe UNSAFE;

    private static final long stateOffset;
    static {
        try {
            UNSAFE = getUnsafeInstance();
            Class<?> ak = MyCasFailLock.class;
            stateOffset = UNSAFE.objectFieldOffset
                    (ak.getDeclaredField("state"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    //使用方法
    private static Unsafe getUnsafeInstance() throws Exception{
        Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeInstance.setAccessible(true);
        return (Unsafe) theUnsafeInstance.get(Unsafe.class);
    }



    public void lock(){
        //修改不成功代表枪锁失败，一直自旋
        while(!UNSAFE.compareAndSwapInt(this,stateOffset,0,1)){
            waiter.add(Thread.currentThread());
            LockSupport.park();
            waiter.remove(Thread.currentThread());
        }
    }

    public void unLock(){
        if(UNSAFE.compareAndSwapInt(this,stateOffset,1,0)){
           Object[] threads = waiter.toArray();
           //依次唤醒，有公平性可言
           for(Object t: threads){
               LockSupport.unpark((Thread) t);
           }
        }
    }

}


class TestMyCasFailLock{
    MyCasFailLock casLock = new MyCasFailLock();

    public static void main(String[] args) {
        TestMyCasFailLock testMyCasLock = new TestMyCasFailLock();

        new Thread(()->{
            testMyCasLock.add();
        }).start();

        new Thread(()->{
            testMyCasLock.add();
        }).start();
    }


    public void add(){
        try{
            System.out.println(Thread.currentThread().getName()+"抢锁中......");
            casLock.lock();
            System.out.println(Thread.currentThread().getName()+"抢锁成功");
        }finally {
            casLock.unLock();
            System.out.println(Thread.currentThread().getName()+"释放锁成功");
        }
    }

}




